//
//  VideoPlayerController.swift
//  teacher
//
//  Created by raniys on 2018/10/22.
//

import UIKit
import AVKit
import AVFoundation
import CoreMedia
import SnapKit

class VideoPlayerController: UIViewController {

    // MARK: - Properties
    var isLandscaped = false

    var videoUrl: URL?

    var avAsset: AVAsset? {
        didSet {
            guard let asset = avAsset else { return }
            videoPlayer = CYVideoPlayer()
            videoPlayer?.delegate = self
            videoPlayer?.avAsset = asset
        }
    }

    var videoPlayer: CYVideoPlayer?
    var videoPlayerLayer: AVPlayerLayer?
    
    var backgroundView: UIView!
    var videoView: UIView!
    var playVideoButton: UIButton!
    var closeButton: UIButton!
    var videoControlView: UIView!
    var playButton: UIButton!
    var videoSlider: UISlider!
    var playTimeLabel: UILabel!
    var totalTimeLabel: UILabel!
    var rotationButton: UIButton!
    var progressActivity: UIActivityIndicatorView!
    
    
    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    var orientationMask: UIInterfaceOrientationMask = .portrait
    

    // MARK: - Life Cycle

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        configureViews()
        if let url = videoUrl {
            avAsset = AVAsset(url: url)
        }
    }

    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return orientationMask
    }
    
    override var shouldAutorotate: Bool {
        return true
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        appDelegate.shouldRotate = true
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        appDelegate.shouldRotate = false
    }


    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)

        switch UIDevice.current.orientation {
        case .portrait:
            isLandscaped = false
        case .landscapeLeft, .landscapeRight:
            isLandscaped = true
        default:
            return
        }
    }

    override var prefersStatusBarHidden: Bool {
        return isLandscaped
    }

    override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation {
        return .slide
    }

    override func viewDidLayoutSubviews() {
        
        // videoView.bounds sometimes nil when loadPlayer,
        // so reset the frame for videoPlayerLayer
        CATransaction.begin()
        CATransaction.setDisableActions(true)
        videoPlayerLayer?.frame = videoView.bounds
        CATransaction.commit()
    }
    
    deinit {
        videoPlayer?.pause()
        videoPlayer?.delegate = nil
        videoPlayer = nil
        print("VideoPlayerController \(#function)")
    }


    // MARK: - Video

    func loadPlayer(_ player: AVPlayer) {
        let playerLayer = AVPlayerLayer(player: player)
        playerLayer.player = player
        playerLayer.videoGravity = AVLayerVideoGravity.resizeAspect
        playerLayer.frame = videoView.bounds
        videoPlayerLayer = playerLayer
        videoView.layer.addSublayer(playerLayer)
    }

    func resetViewsForVideo(_ playing: Bool) {
        if !playing {
            playButton.isSelected = false
        } else {
            playButton.isSelected = true
            playVideoButton.isHidden = true
        }
    }

    @objc func onCloseTapped() {
        if navigationController?.viewControllers.count ?? 0 > 1 {
            navigationController?.popViewController(animated: false)
        } else {
            dismiss(animated: false, completion: nil)
        }
    }

    @objc func onVideoSliderMoved(_ slider: UISlider, event: UIEvent) {
        guard let player = videoPlayer else { return }

        let value = slider.value

        if let touchEvent = event.allTouches?.first {
            switch touchEvent.phase {
            case .began:
                player.pause()
            case .moved:
                player.seek(to: Double(value))
            case .ended:
                player.seek(to: Double(value))
                player.play()
            case .cancelled:
                player.play()
            case .stationary:
                player.seek(to: Double(value))
            }
        }
    }

    @objc func onVideoTapped() {
        guard let player = videoPlayer else { return }

        if player.isPlaying() {
            player.pause()
            resetViewsForVideo(false)
        } else {
            player.play()
            resetViewsForVideo(true)
        }
    }

    @objc func onPlayVideoTapped() {
        guard let player = videoPlayer, !player.isPlaying() else { return }
        player.play()
        resetViewsForVideo(true)
    }

    @objc func onSingleTapped() {
        if videoControlView.isHidden {
            videoControlView.isHidden = false
        } else {
            videoControlView.isHidden = true
        }

    }
    

    // MARK: - Video rotation

    @objc func onRotationTapped(_ sender: UIButton) {
        if sender.isSelected {
            sender.isSelected = false
            
            orientationMask = .portrait
            let value = UIInterfaceOrientation.portrait.rawValue
            UIDevice.current.setValue(value, forKey: "orientation")
        } else {
            sender.isSelected = true

            orientationMask = .landscape
            let value = UIInterfaceOrientation.landscapeRight.rawValue
            UIDevice.current.setValue(value, forKey: "orientation")
        }
        self.videoPlayerLayer?.frame = self.videoView.bounds
    }
    
//    func downloadVideo(for url: URL) {
//        let filePath = URL(fileURLWithPath: TEMP_DIRECTORY_PATH).appendingPathComponent(url.lastPathComponent)
//        guard !FileManager.default.fileExists(atPath: filePath.path) else {
//            saveVideoToLibrary(filePath)
//            return
//        }
//
//        HUD.show(.labeledProgress(title: "正在处理", subtitle: "正在下载..."))
//        let destination: DownloadRequest.DownloadFileDestination = { _, _ in
//            return (filePath, [.removePreviousFile, .createIntermediateDirectories])
//        }
//
//        Alamofire.download(url, to: destination).response { response in
//            if let error = response.error {
//                HUD.hide()
//                HUD.label("下载失败, \(error.localizedDescription)")
//            } else {
//                self.saveVideoToLibrary(filePath)
//            }
//        }
//
//    }


    // MARK: Configuration

    func configureViews() {

        backgroundView = {
            let view = UIView()
            view.backgroundColor = .black
            return view
        }()

        videoView = {
            let view = UIView()
            view.backgroundColor = .clear
            return view
        }()

        playVideoButton = {
            let button = UIButton(type: .custom)
            button.setImage(UIImage(named: "icon_big_pause"), for: .normal)
            button.addTarget(self, action: #selector(self.onPlayVideoTapped), for: .touchUpInside)
            button.isHidden = true
            return button
        }()

        closeButton = {
            let button = UIButton(type: .custom)
            button.setImage(UIImage(named: "icon_close_off"), for: .normal)
            button.addTarget(self, action: #selector(self.onCloseTapped), for: .touchUpInside)
            return button
        }()

        videoControlView = {
            let view = UIView()
            view.backgroundColor = UIColor.black.withAlphaComponent(0.02)
            return view
        }()

        playButton = {
            let button = UIButton(type: .custom)
            button.setImage(UIImage(named: "icon_small_pause"), for: .normal)
            button.setImage(UIImage(named: "icon_small_paly"), for: .selected)
            button.contentHorizontalAlignment = .right
            button.addTarget(self, action: #selector(self.onVideoTapped), for: .touchUpInside)
            button.isEnabled = false
            return button
        }()

        videoSlider = {
            let slider = UISlider()
            slider.setThumbImage(UIImage(named: "slider_icon"), for: .normal)
            slider.minimumTrackTintColor = UIColor.white.withAlphaComponent(0.8)
            slider.maximumTrackTintColor = UIColor(hex: 0x3E3C46, alpha: 0.5)
            slider.isContinuous = false
            slider.addTarget(self, action: #selector(self.onVideoSliderMoved(_:event:)), for: .allEvents)
            slider.isEnabled = false
            return slider
        }()

        playTimeLabel = {
            let label = UILabel()
            label.text = "00:00"
            label.textColor = UIColor.white
            label.font = UIFont.size(14)
            label.textAlignment = .right
            return label
        }()

        totalTimeLabel = {
            let label = UILabel()
            label.text = "00:00"
            label.textColor = UIColor.white
            label.font = UIFont.size(14)
            label.textAlignment = .left
            return label
        }()

        rotationButton = {
            let button = UIButton(type: .custom)
            button.setImage(UIImage(named: "icon_turn_right"), for: .normal)
            button.setImage(UIImage(named: "icon_turn_left"), for: .selected)
            button.contentHorizontalAlignment = .left
            button.addTarget(self, action: #selector(self.onRotationTapped(_:)), for: .touchUpInside)
            return button
        }()

        progressActivity = {
            let activity = UIActivityIndicatorView(style: .whiteLarge)
            activity.startAnimating()
            activity.hidesWhenStopped = true
            return activity
        }()

        view.addSubview(backgroundView)
        backgroundView.snp.makeConstraints { (make) in
            make.edges.equalToSuperview()
        }

        view.addSubview(progressActivity)
        progressActivity.snp.makeConstraints { (make) in
            make.center.equalToSuperview()
        }

        let tap = UITapGestureRecognizer(target: self, action: #selector(self.onSingleTapped))
        videoView.addGestureRecognizer(tap)

        backgroundView.addSubview(videoView)
        videoView.snp.makeConstraints { (make) in
            make.edges.equalToSuperview()
        }

        backgroundView.addSubview(playVideoButton)
        playVideoButton.snp.makeConstraints { (make) in
            make.center.equalToSuperview()
        }

        backgroundView.addSubview(closeButton)
        closeButton.snp.makeConstraints { (make) in
            make.top.equalTo(view.safeArea.top).offset(24)
            make.leading.equalToSuperview().offset(16)
        }

        backgroundView.addSubview(videoControlView)
        videoControlView.snp.makeConstraints { (make) in
            make.leading.equalToSuperview()
            make.trailing.equalToSuperview()
            make.height.equalTo(24)
            make.bottom.equalTo(view.safeArea.bottom).offset(-40)
        }

        videoControlView.addSubview(playButton)
        playButton.snp.makeConstraints { (make) in
            make.leading.equalToSuperview()
            make.centerY.equalToSuperview()
            make.size.equalTo(CGSize(width: 40, height: 20))
        }

        videoControlView.addSubview(playTimeLabel)
        playTimeLabel.snp.makeConstraints { (make) in
            make.left.equalTo(playButton.snp.right).offset(16)
            make.centerY.equalToSuperview()
            make.width.equalTo(40)
        }

        videoControlView.addSubview(rotationButton)
        rotationButton.snp.makeConstraints { (make) in
            make.centerY.equalToSuperview()
            make.trailing.equalToSuperview()
            make.size.equalTo(CGSize(width: 40, height: 24))
        }

        videoControlView.addSubview(totalTimeLabel)
        totalTimeLabel.snp.makeConstraints { (make) in
            make.centerY.equalToSuperview()
            make.right.equalTo(rotationButton.snp.left).offset(-16)
        }

        videoControlView.addSubview(videoSlider)
        videoSlider.snp.makeConstraints { (make) in
            make.left.equalTo(playTimeLabel.snp.right).offset(8)
            make.right.equalTo(totalTimeLabel.snp.left).offset(-8)
            make.centerY.equalToSuperview()
            make.height.equalTo(10)
        }

    }

}


extension UIView {
    var safeArea: ConstraintBasicAttributesDSL {
        
        #if swift(>=3.2)
        if #available(iOS 11.0, *) {
            return self.safeAreaLayoutGuide.snp
        }
        return self.snp
        #else
        return self.snp
        #endif
    }
}


extension VideoPlayerController: CYVideoPlayerDelegate {
    func videoPlayer(videoPlayer: CYVideoPlayer, layerDisplay avPlayer: AVPlayer) {
        loadPlayer(avPlayer)
    }

    func videoPlayer(videoPlayer: CYVideoPlayer, readyToPlayWith totalDuration: Double) {
        progressActivity.stopAnimating()
        playButton.isEnabled = true
        videoSlider.isEnabled = true

        guard
            !totalDuration.isNaN,
            totalDuration > 0,
            let duration = Int(String(format: "%0.0f", totalDuration)) else { return }
        print("VideoPlayerReady to play duration: \(totalDuration)")
        videoSlider.maximumValue = Float(totalDuration)

        let min = duration / 60
        let sec = duration % 60
        totalTimeLabel.text = String(format: "%02d:%02d", min, sec)

        videoPlayer.play()
        resetViewsForVideo(true)
    }

    func didFinishedPlaying(videoPlayer: CYVideoPlayer) {
        videoPlayer.pause()
        playVideoButton.isHidden = false
        resetViewsForVideo(false)
    }

    func videoPlayer(videoPlayer: CYVideoPlayer, failedToPrepareWith error: Error) {
        print("视频播放失败: \(error.localizedDescription)")
    }

    func videoPlayer(videoPlayer: CYVideoPlayer, playTo duration: Double) {
        
        if duration > videoPlayer.totalDuration {
            videoPlayer.resetDisplay()
        } else {
            videoSlider.setValue(Float(duration), animated: true)

            if let duration = Int(String(format: "%0.0f", duration)) {
                let min = duration / 60
                let sec = duration % 60
                playTimeLabel.text = String(format: "%02d:%02d", min, sec)
            }
        }
    }
}
